from socket import *
from MineInfo import MineInfo
from MineMove import MineMove
from MineAgent import MineAgent

class MineClient:
    """Python port of Patric Jensfels MineClient.java by Simon Pettersson"""

    def __init__(self,hostname = 'localhost',port=5555):
        self.sock = None
        self.agent = None
        self.hostname = hostname
        self.port = port

    def connect(self,hostname,port):
        """Connects to a host"""
        print "Trying to connect to " + str(hostname) + " on port " + str(port)
        try:
            self.sock = socket(AF_INET,SOCK_STREAM)
            print "Socket created"
            self.sock.connect((hostname,port))
            return True
        except error, (value,message):
            print "Error connecting to " + hostname + ": " + message
        self.sock = None
        return False

    def disconnect(self):
        """Closes the connection to the host."""
        if self.sock == None:
            return True
        print "Closing connection to server"
        try:
            self.sock.close()
        except:
            print "Error closing connection to server"
            return False
        self.sock = None
        return True
    
    def receive(self):
        """Python implementation of the concept of java streams. This will read
        from the server until a \n character is received"""
        if self.sock == None:
            return None
        msg = ''
        c = ''
        while c != '\n':
            c = self.sock.recv(1)
            if c == '':
                raise RuntimeError, 'Error, socket connection broken'
            msg+=c
        return msg[:-1]

    def send(self,msg):
        """Sends a string to the java server. To comply with the java streams we append
        a '\n' to the string before sending."""
        if self.sock == None:
            return False
        msg+='\n'
        totalsent = 0
        while totalsent < len(msg):
            sent = self.sock.send(msg[totalsent:])
            if sent == 0:
                raise RuntimeError, 'Error, socket connection broken'
            totalsent+=sent
        return True

    def playGame(self,name,agent):
        """Plays a game on the server."""
        self.agent = agent

        if not self.connect(self.hostname, self.port):
            return False

        self.send(name)
        while(True):
            msg = self.receive()
            #print 'msg=\"' + msg + '\"'
            if msg == 'MOVE':
                move = self.agent.getNextMove()
                if move != None:
                    if move.move == MineMove.OPEN_SQUARE:
                        self.send("OPEN " + str(move.X) + " " + str(move.Y))
                    elif move.move == MineMove.PEEK_SQUARE:
                        self.send("PEEK " + str(move.X) + " " + str(move.Y))
                    elif move.move == MoneMove.STOP:
                        self.send("STOP")
                    else:
                        print "Unexpected command " + str(move.move) + "!"
                        continue
                else:
                    print "Could not get agent move!"
                    continue
            elif msg.startswith("START"):
                print ""
                print "STARTING NEW GAME"
                print ""
                cmd = msg.split(" ")
                if cmd != None and len(cmd) == 7:
                    self.agent.startNewGame(int(cmd[1]),
                                            int(cmd[2]),
                                            int(cmd[3]),
                                            int(cmd[4]),
                                            int(cmd[5]),
                                            int(cmd[6]))
            elif msg.startswith("SQUARE_INFO"):
                cmd = msg.split(" ")
                if cmd != None and len(cmd) == 5:
                    mineInfo = MineInfo()
                    mineInfo.infoType = MineInfo.SQUARE_INFO
                    mineInfo.playerID = int(cmd[1])
                    mineInfo.X = int(cmd[2])
                    mineInfo.Y = int(cmd[3])
                    mineInfo.value = int(cmd[4])
                    self.agent.handleInfo(mineInfo)
            elif msg.startswith("ILLEGAL_MOVE"):
                cmd = msg.split(" ")
                if cmd != None and len(cmd) == 4:
                    mineInfo = MineInfo()
                    mineInfo.infoType = MineInfo.ILLEGAL_MOVE
                    mineInfo.playerID = int(cmd[1])
                    mineInfo.X = int(cmd[2])
                    mineInfo.Y = int(cmd[3])
                    self.agent.handleInfo(mineInfo)
            elif msg.startswith("ALREADY_OPEN"):
                cmd = msg.split(" ")
                if cmd != None and len(cmd) == 4:
                    mineInfo = MineInfo()
                    mineInfo.infoType = MineInfo.ALREADY_OPEN
                    mineInfo.playerID = int(cmd[1])
                    mineInfo.X = int(cmd[2])
                    mineInfo.Y = int(cmd[3])
                    self.agent.handleInfo(mineInfo)
            elif msg.startswith("ALREADY_PEEKED"):
                cmd = msg.split(" ")
                if cmd != None and len(cmd) == 2:
                    mineInfo = MineInfo()
                    mineInfo.infoType = MineInfo.ALREADY_PEEKED
                    mineInfo.playerID = int(cmd[1])
                    self.agent.handleInfo(mineInfo)
            elif msg.startswith("PLAYER_STOPPED"):
                cmd = msg.split(" ")
                if cmd != None and len(cmd) == 2:
                    mineInfo = MineInfo()
                    mineInfo.infoType = MineInfo.PLAYER_STOPPED
                    mineInfo.playerID = int(cmd[1])
                    self.agent.handleInfo(mineInfo)
            elif msg.startswith("UNKNOWN_CMD"):
                mineInfo = MineInfo()
                mineInfo.infoType = MineInfo.UNKNOWN_CMD
                mineInfo.unknownCmd = msg[12:]
                self.agent.handleInfo(mineInfo)
            elif msg.startswith("DONE"):
                cmd = msg.split(" ")
                if cmd != None and len(cmd) == 2:
                    mineInfo = MineInfo()
                    mineInfo.infoType = MineInfo.SCORE
                    mineInfo.score = int(cmd[1])
                    self.agent.handleInfo(mineInfo)

